package com.lnsoft.cac.server.handle.codec;

import com.lnsoft.cac.server.Entity.Command;
import com.sun.jmx.remote.internal.ArrayQueue;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelId;
import lombok.Data;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.ConcurrentLinkedQueue;


//  电压监测设备的信息、会话信息、帧报文处理状态信息等；
@Data
public class Device {

    /*
     * 当前CAC所处的和监测设备不同交互过程中（交互过程根据不同场景，使用1对一问一答帧报文，或者使用多对一问一答帧报文）；
     * 0：没有交互
     * 1：心跳监测
     * 2：数据上传
     * 3：数据请求
     * 4：配置/状态交互
     * 5：流量上送
     * 6：事件上送
     * 7：远程更新
     */
    private volatile int process = 0;
    /*
     * 未收到确认帧超时次数(超过一定次数将制定报文从发机制)
     * 当监测设备按心跳周期发送心跳报文、并且监测设备一直不能发送业务报文帧的确认帧的情况下(设备连接在线，但是确认帧超时)，receiveCfmTimeOut将是必要的；
     */
    private int receiveCfmTimeOut = 0;

    //  监测设备的17bytes的设备编码
    private volatile String clientId;

    //  监测设备对应的channelId
    private volatile ChannelId channelId;

    //  最后一次心跳时间/毫秒
    private long lastHeartBeatTime;

    //  设备的心跳间隔/毫秒
    private long heatBeatIdleTime;

    //  连接空闲超时次数；（超过3次 认为设备离线、将channelId置null）
    private int idleTimeOutNumber = 0;

    //  服务端端口号
    private int serverPort;

    private ByteBuf byteBuf = Unpooled.directBuffer(); // 堆外内存

    /*
     * 监测终端向cac主动发送打开状态：1：打开，2：关闭
     * （监测终端打开状态以CAC收到主发报文为准，不以监测装置发送时为准（对于cac来说，是未知的））
     * 上行通道和下行通道是必须是单行；因为在设计文档中注明了：发送方必须接收到到确认帧之后才能发下一帧，接收方必须先发送确认报文才能主动发送报文；
     */
    private volatile int deviceSend = 2;
    //  cac向监测设备主动发送打开状态：1：打开，2：关闭
    private int cacSend = 2;
    //  装置向cac发送的帧序列号
    private volatile int fraSerNum4Dev;
    //  cac向装置发送的帧序列号
    private volatile int fraSerNum4CAC;
    //  设备接收的指令列表
    private ConcurrentLinkedQueue<Command> cagCmdList = new ConcurrentLinkedQueue<>();

    public int getFraSerNum4CAC() {
        if ((fraSerNum4CAC + 1) < 255){
            setFraSerNum4CAC(fraSerNum4CAC + 1);
        } else {
            setFraSerNum4CAC(0);
            return 0;
        }
        return fraSerNum4CAC + 1;
    }

    /*
     * 检查缓存指令中是否有指定类型的、已完成下发、还没有返回执行结果的指令；
     * GETCONFIG:(应用场景，下同)读配置交互:(含义，下同)CAG获取CAC及其管辖电压监测装置的配置信息;
     * SETCONFIG:写配置交互:CAG返回配置信息供CAC对自身及其管辖电压监测装置的配置信息进行更新;
     * GETEVENT:事件召唤:CAG获取电压监测装置的事件;
     * GETDATA:分钟数据召唤:CAG获取CAC或所辖监测装置的电压监测数据;
     * GETDSTATDATA:日统计数据召唤:CAG获取CAC或监测装置的日统计数据;
     * GETMSTATDATA:月统计数据召唤:CAG获取CAC或监测装置的月统计数据;
     * UPDATENOTICE:更新通知:CAG通知CAC或所属监测装置版本更新;
     * RESTART:重启命令:CAG通知CAC或所属装置进行重启;
     */
//    public Command hasCmd(String cmdType, String action, int cmdStatus) {
//        for (Command cagCmd : cagCmdList) {
//            if (action != null
//                    && cagCmd.getAction().equals(action)
//                    && cagCmd.getCmd_type().equals(cmdType)
//                    && cagCmd.getCmdStatus() == cmdStatus) {
//                return cagCmd;
//            }
//            if (action == null
//                    && cagCmd.getCmd_type().equals(cmdType)
//                    && cagCmd.getCmdStatus() == cmdStatus) {
//                return cagCmd;
//            }
//        }
//        return null;
//    }

    /*
    *   设备接收到指令之后首先给到“当前指令”，如果连续接收到多个指令，则将指令缓存到“指令列表”;
    *   当“当前指令”执行完成、超时等原因指令生命周期终止时，将缓存的指令按顺序取出放到“当前指令”。
    * */
    private Command currentCmd = null;
}
